跳到主要内容

05-06 开发工具

阅读量

0

阅读人次

0

05 嵌入式C语言编译器

GCC与gcc有什么不同?

  • GCC(GNU Compiler Collection)
    • GNU编译器集合,包含众多语言的编译器:C,C++,Java,D,Objective-C,etc.
  • gcc:特指GCC中的C语言编译器

GCC VS. 嵌入式

  • 多数嵌入式操作系统都基于GCC进行源码编译:Linux,VxWorks,Android,etc.

实际开发中的使用

  • 内核开发:gcc
  • 应用开发:gcc/g++/gdc

什么是交叉编译

  • 背景:嵌入式设备往往资源受限,不可能在嵌入式上直接对处理器进行编程。
  • 解决方案:在开发主机(PC)上对源码进行编译,最终生成目标主机(嵌入式设备)的可执行程序。

gcc是如何进行交叉编译的?

  • 配置目标主机的编译工具链(如:arm-linux)
  • 配置工具链的具体版本
    • 根据具体的目标代码选择相应的工具链版本
    • 正确使用关于硬件体系结构的特殊编译选项

案例:大型企业嵌入式开发环境

初识编译器

你不知道的事...

拓展问题:如何理解"多语言混合开发"?

多语言混合开发方式一

行业案例:.net framework

多语言混合开发方式二

行业案例: QQ

多语言混合开发方式三

行业案例:Eclipse

gcc关键编译选项

  • 预处理指令:gcc -E file.c -o file.i

  • 编译指令:gcc -S file.i -o file.s

  • 汇编指令:gcc -c file.s -o file.o

  • 生成映射文件:gcc -WI,-Map=test.map file.c

  • 宏定义:gcc -D'TEST="Test"' file.c

  • 获取系统头文件路径:gcc -v file.c

  • 生成依赖关系

    • 获取目标的完整依赖关系:gcc -M test.c
    • 获取目标的部分依赖关系:gcc -MM test.c
  • 指定库文件及库文件搜索路径

    • -L选项:指定库文件的搜索路径
    • -l选项:指定库文件
  • gcc test.c -L. -lfunc

06 开发中的辅助工具

什么是开发环境

  • 构建环境:代码编写,程序编译,版本控制(可选)
  • 调试环境:用于定位问题的辅助工具集
  • 测试环境:用于验证目标程序是否满足用户的显性需求和隐性需求

嵌入式开发中的时间分配

  • 代码编写即目标构建(20%)
  • 测试,调试,bug修复(80%)

问题:如何提高开发效率?

工欲善其事,必先利其器!

GNU为GCC编译器提供了配套的辅助工具集(Binutils),http://www.gnu.org/software/binutils。

工具名功能简介
addr2line将代码地址转换为对应的程序行号
strip剔除可执行程序中的调试信息
ar将目标文件打包成为静态库
nm列出目标文件中的符号及对应地址
objdump查看程序段信息及反汇编
size查看目标文件中的段大小
strings查看目标文件中的字符串
readelf用于读取 ELF(Executable and Linkable Format)格式文件的详细信息

addr2line

  • 将指定地址转换为对应的文件名和行号
  • 常用于分析和定位内存访问错误的问题
void func() {
/*oops!!*/
*g_pointer = (int)"Hello World";
return;
}

addr2line示例:定位0地址访问

  1. 开启core dump选项:ulimit -c unlimited
  2. 运行程序,并生成崩溃时的core文件,执行导致程序崩溃的测试用例
  3. 读取core文件,获取IP寄存器的值(0x08048000),dmesg core
  4. 使用addr2line定位代码行,addr2line 0x08048000 -f -e test.out

strip

  • 剔除程序文件中的调试信息,减少目标程序的大小
  • 一般在程序发布前都需要将调试信息剔除
  • 过多的调试信息可能影响程序的执行效率 strip test.out

注意事项

  • 几乎所有的调试辅助工具都依赖于目标文件中的调试信息
  • 调试信息的运用能够快速定位问题
  • 使用gcc编译程序时使用-g选项生成调试信息
  • 发布程序时再考虑是否使用strip剔除调试信息

ar

  • 打包目标文件:ar crs libname.a x.o y.o
  • 解压目标文件:ar x libname.a

nm

  • 列出目标文件中的标识符(变量名,函数名)
  • 输出结果由三部分组成:(地址,断,标识符)

示例:

  • 段标识说明
段标识说明
A地址值在链接过程中不会发生改变
B或b标识符位于未初始化数据段(.bss)
C未定义存储段的标识符,链接时决定段位置
D或d标识符位于数据段(.data)
N调试专用标识符
R或r标识符位于只读存储区(.rdata)
T或t标识符位于代码段(.text)
U未定义的标识符

objdump

  • 反汇编目标文件,查看汇编到源码的映射
    • objdump -d func.o
    • objdump -S func.o
  • 查找目标文件中的详细段信息
    • objdump -h test.out

objdump -h的输出说明

符号说明
Idx段下标
Name段标识符(名字)
Size段所占空间的大小
VMA段起始位置的虚存地址
LMA段在存储空间中的加载地址
File off段在目标文件中的相对位置
Algn段的边界对齐字节数

size

获取目标文件中的所有段大小

  • size test.out

strings

获取目标文件中的所有字符串常量

  • strings test.out

readelf

使用readelf查找程序所需的动态库:

readelf --dynamic ./exetuable | grep NEEDED

输出如下:

0x0000000000000001 (NEEDED) Shared library: [librwp2p.so]
0x0000000000000001 (NEEDED) Shared library: [libzlog.so]
0x0000000000000001 (NEEDED) Shared library: [libcrypto.so.1.0.0]
0x0000000000000001 (NEEDED) Shared library: [libssl.so.1.0.0]
......
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]